library(tidyverse) # for graphing and data cleaning
library(tidymodels) # for modeling
library(naniar) # for analyzing missing values
library(vip) # for variable importance plots
library(glmnet) # for regularized regression, including LASSO
theme_set(theme_minimal())
hotels <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-02-11/hotels.csv')
Setting Up Git and Github in RStudio
Here is my Github link.
Creating a Website
- Website Link
- Here is the link to my website.
Machine Learning review and intro to tidymodels
- Read about the hotel booking data,
hotels, on the Tidy Tuesday page it came from. There is also a link to an article from the original authors. The outcome we will be predicting is called is_canceled.
- Without doing any analysis, what are some variables you think might be predictive and why?
- There are a few variables that could be predictive, however
previous_cancellations definitely stands out. It is reasonable to assume that if someone has canceled before, they could possiblky cancel again. booking_changes could also be predictive, as someone who makes a bunch of changes is likely to be unsure about their booking and one of the changes that they could make could be canceling the stay. Finally, a third variable that could be predictive is customer_type, as the type of customer could make it easier or more difficult to cancel the stay.
- What are some problems that might exist with the data? You might think about how it was collected and who did the collecting.
- One issue with the way that the data was collected is that there are almost twice as many observations for the city hotel as the resort hotel, which could introduce bias into the data. The data for canceled bookings could also be less accurate, as variables such as adults, children, and babies could be inaccurate due to the family or group never showing up. Therefore, there could be bias towards non-canceled bookings based on how the data was collected. The
reservation_status variable is also a bit redundant, as it states whether someone canceled their reservation or not, which is already given in the is_canceled variable. Finally, each reservation is missing a unique identifier, so
- If we construct a model, what type of conclusions will be able to draw from it?
- If we construct a model, the type of conclusions that we’ll be able to draw from it are likely to be which variables are most important to determine the likelihood of cancellation. This could easily be achieved using the LASSO technique to analyze variable importance.
- Create some exploratory plots or table summaries of the data, concentrating most on relationships with the response variable. Keep in mind the response variable is numeric, 0 or 1. You may want to make it categorical (you also may not). Be sure to also examine missing values or other interesting values.
hotels %>%
ggplot(aes(x = hotel)) +
geom_bar(fill = "blue") +
facet_wrap(vars(is_canceled))

hotels %>%
ggplot(aes(x = customer_type)) +
geom_bar(fill = "red") +
facet_wrap(vars(is_canceled))

hotels %>%
ggplot(aes(x = previous_cancellations)) +
geom_bar(fill = "orange") +
xlim(0,3) +
ylim(0,7000) +
facet_wrap(vars(is_canceled))
## Warning: Removed 252 rows containing non-finite values (stat_count).
## Warning: Removed 4 rows containing missing values (geom_bar).

hotels %>%
ggplot(aes(x = adults)) +
geom_bar(fill = "green") +
xlim(0,5) +
facet_wrap(vars(is_canceled))
## Warning: Removed 14 rows containing non-finite values (stat_count).
## Warning: Removed 3 rows containing missing values (geom_bar).

hotels %>%
ggplot(aes(x = children)) +
geom_bar(fill = "green") +
xlim(0,5) +
ylim(0,2500) +
facet_wrap(vars(is_canceled))
## Warning: Removed 5 rows containing non-finite values (stat_count).
## Warning: Removed 3 rows containing missing values (geom_bar).

hotels %>%
ggplot(aes(x = babies)) +
geom_bar(fill = "green") +
xlim(0,5) +
ylim(0,200) +
facet_wrap(vars(is_canceled))
## Warning: Removed 2 rows containing non-finite values (stat_count).
## Warning: Removed 3 rows containing missing values (geom_bar).

- First, we will do a couple things to get the data ready, including making the outcome a factor (needs to be that way for logistic regression), removing the year variable and some reservation status variables, and removing missing values (not NULLs but true missing values). Split the data into a training and test set, stratifying on the outcome variable,
is_canceled. Since we have a lot of data, we’re going to split the data 50/50 between training and test. I have already set.seed() for you. Be sure to use hotels_mod in the splitting.
hotels_mod <- hotels %>%
mutate(is_canceled = as.factor(is_canceled)) %>%
mutate(across(where(is.character), as.factor)) %>%
select(-arrival_date_year,
-reservation_status,
-reservation_status_date) %>%
add_n_miss() %>%
filter(n_miss_all == 0) %>%
select(-n_miss_all)
set.seed(494)
hotel_split <- initial_split(hotels_mod,
prop = 0.5)
hotel_train <- training(hotel_split)
hotel_test <- testing(hotel_split)
- Pre-processing
hotel_recipe <- recipe(is_canceled ~.,
data = hotel_train) %>%
step_mutate_at(children, babies, previous_cancellations,
fn = ~ifelse(. > 0, 1, 0)) %>%
step_mutate_at(agent, company,
fn = ~ifelse(. == "NULL", 1, 0)) %>%
step_mutate(country = fct_lump_n(country, 5)) %>%
step_normalize(all_numeric()) %>%
step_dummy(all_nominal(), -all_outcomes())
hotel_recipe %>%
prep(hotel_train) %>%
juice()
- LASSO model and workflow
- We would want to use a LASSO workflow because LASSO uses an importance coefficient which reduces to zero when the variable is deemed to be not predictive of our outcome variable. This will allow us to reduce the size of our dataset and only focus on our indicator variables that matter.
# lasso_hotel_mod <- linear_reg(penalty = tune(), mode = "regression") %>%
# set_engine("glmnet")
#
# workflow <- workflow() %>%
# add_recipe(hotel_recipe) %>%
# add_model(lasso_hotel_mod)
#
# lasso_hotel_fit <- workflow %>%
# fit(data = hotel_train)
LS0tCnRpdGxlOiAnQXNzaWdubWVudCAjMScKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQoja25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQpgYGAKCmBgYHtyIGxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAgICAgIyBmb3IgZ3JhcGhpbmcgYW5kIGRhdGEgY2xlYW5pbmcKbGlicmFyeSh0aWR5bW9kZWxzKSAgICAgICAgIyBmb3IgbW9kZWxpbmcKbGlicmFyeShuYW5pYXIpICAgICAgICAgICAgIyBmb3IgYW5hbHl6aW5nIG1pc3NpbmcgdmFsdWVzCmxpYnJhcnkodmlwKSAgICAgICAgICAgICAgICMgZm9yIHZhcmlhYmxlIGltcG9ydGFuY2UgcGxvdHMKbGlicmFyeShnbG1uZXQpICAgICAgICAgICAgIyBmb3IgcmVndWxhcml6ZWQgcmVncmVzc2lvbiwgaW5jbHVkaW5nIExBU1NPCmBgYAoKYGBge3IgdGhlbWV9CnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCmBgYAoKYGBge3IgZGF0YSwgY2FjaGU9VFJVRSwgbWVzc2FnZT1GQUxTRX0KaG90ZWxzIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIwLzIwMjAtMDItMTEvaG90ZWxzLmNzdicpCmBgYAoKCiMjIFNldHRpbmcgVXAgR2l0IGFuZCBHaXRodWIgaW4gUlN0dWRpbwoKW0hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGV4ZGVuemxlci9TVEFUNDk0X3NpdGVfRGVuemxlcikgaXMgbXkgR2l0aHViIGxpbmsuCgoKIyMgQ3JlYXRpbmcgYSBXZWJzaXRlCgoqIFdlYnNpdGUgTGluawogICsgW0hlcmVdKGh0dHBzOi8vdXBiZWF0LWhhd2tpbmctYjllZjI2Lm5ldGxpZnkuYXBwKSBpcyB0aGUgbGluayB0byBteSB3ZWJzaXRlLgogIAoqIAoKCiMjIE1hY2hpbmUgTGVhcm5pbmcgcmV2aWV3IGFuZCBpbnRybyB0byBgdGlkeW1vZGVsc2AKCihAKSBSZWFkIGFib3V0IHRoZSBob3RlbCBib29raW5nIGRhdGEsIGBob3RlbHNgLCBvbiB0aGUgVGlkeSBUdWVzZGF5IHBhZ2UgaXQgY2FtZSBmcm9tLiBUaGVyZSBpcyBhbHNvIGEgbGluayB0byBhbiBhcnRpY2xlIGZyb20gdGhlIG9yaWdpbmFsIGF1dGhvcnMuIFRoZSBvdXRjb21lIHdlIHdpbGwgYmUgcHJlZGljdGluZyBpcyBjYWxsZWQgYGlzX2NhbmNlbGVkYC4KCiogV2l0aG91dCBkb2luZyBhbnkgYW5hbHlzaXMsIHdoYXQgYXJlIHNvbWUgdmFyaWFibGVzIHlvdSB0aGluayBtaWdodCBiZSBwcmVkaWN0aXZlIGFuZCB3aHk/CiAgKyBUaGVyZSBhcmUgYSBmZXcgdmFyaWFibGVzIHRoYXQgY291bGQgYmUgcHJlZGljdGl2ZSwgaG93ZXZlciBgcHJldmlvdXNfY2FuY2VsbGF0aW9uc2AgZGVmaW5pdGVseSBzdGFuZHMgb3V0LiBJdCBpcyByZWFzb25hYmxlIHRvIGFzc3VtZSB0aGF0IGlmIHNvbWVvbmUgaGFzIGNhbmNlbGVkIGJlZm9yZSwgdGhleSBjb3VsZCBwb3NzaWJsa3kgY2FuY2VsIGFnYWluLiBgYm9va2luZ19jaGFuZ2VzYCBjb3VsZCBhbHNvIGJlIHByZWRpY3RpdmUsIGFzIHNvbWVvbmUgd2hvIG1ha2VzIGEgYnVuY2ggb2YgY2hhbmdlcyBpcyBsaWtlbHkgdG8gYmUgdW5zdXJlIGFib3V0IHRoZWlyIGJvb2tpbmcgYW5kIG9uZSBvZiB0aGUgY2hhbmdlcyB0aGF0IHRoZXkgY291bGQgbWFrZSBjb3VsZCBiZSBjYW5jZWxpbmcgdGhlIHN0YXkuIEZpbmFsbHksIGEgdGhpcmQgdmFyaWFibGUgdGhhdCBjb3VsZCBiZSBwcmVkaWN0aXZlIGlzIGBjdXN0b21lcl90eXBlYCwgYXMgdGhlIHR5cGUgb2YgY3VzdG9tZXIgY291bGQgbWFrZSBpdCBlYXNpZXIgb3IgbW9yZSBkaWZmaWN1bHQgdG8gY2FuY2VsIHRoZSBzdGF5LiAKICAKKiBXaGF0IGFyZSBzb21lIHByb2JsZW1zIHRoYXQgbWlnaHQgZXhpc3Qgd2l0aCB0aGUgZGF0YT8gWW91IG1pZ2h0IHRoaW5rIGFib3V0IGhvdyBpdCB3YXMgY29sbGVjdGVkIGFuZCB3aG8gZGlkIHRoZSBjb2xsZWN0aW5nLgogICsgT25lIGlzc3VlIHdpdGggdGhlIHdheSB0aGF0IHRoZSBkYXRhIHdhcyBjb2xsZWN0ZWQgaXMgdGhhdCB0aGVyZSBhcmUgYWxtb3N0IHR3aWNlIGFzIG1hbnkgb2JzZXJ2YXRpb25zIGZvciB0aGUgY2l0eSBob3RlbCBhcyB0aGUgcmVzb3J0IGhvdGVsLCB3aGljaCBjb3VsZCBpbnRyb2R1Y2UgYmlhcyBpbnRvIHRoZSBkYXRhLiBUaGUgZGF0YSBmb3IgY2FuY2VsZWQgYm9va2luZ3MgY291bGQgYWxzbyBiZSBsZXNzIGFjY3VyYXRlLCBhcyB2YXJpYWJsZXMgc3VjaCBhcyBhZHVsdHMsIGNoaWxkcmVuLCBhbmQgYmFiaWVzIGNvdWxkIGJlIGluYWNjdXJhdGUgZHVlIHRvIHRoZSBmYW1pbHkgb3IgZ3JvdXAgbmV2ZXIgc2hvd2luZyB1cC4gVGhlcmVmb3JlLCB0aGVyZSBjb3VsZCBiZSBiaWFzIHRvd2FyZHMgbm9uLWNhbmNlbGVkIGJvb2tpbmdzIGJhc2VkIG9uIGhvdyB0aGUgZGF0YSB3YXMgY29sbGVjdGVkLiBUaGUgYHJlc2VydmF0aW9uX3N0YXR1c2AgdmFyaWFibGUgaXMgYWxzbyBhIGJpdCByZWR1bmRhbnQsIGFzIGl0IHN0YXRlcyB3aGV0aGVyIHNvbWVvbmUgY2FuY2VsZWQgdGhlaXIgcmVzZXJ2YXRpb24gb3Igbm90LCB3aGljaCBpcyBhbHJlYWR5IGdpdmVuIGluIHRoZSBgaXNfY2FuY2VsZWRgIHZhcmlhYmxlLiBGaW5hbGx5LCBlYWNoIHJlc2VydmF0aW9uIGlzIG1pc3NpbmcgYSB1bmlxdWUgaWRlbnRpZmllciwgc28gCiAgCiogSWYgd2UgY29uc3RydWN0IGEgbW9kZWwsIHdoYXQgdHlwZSBvZiBjb25jbHVzaW9ucyB3aWxsIGJlIGFibGUgdG8gZHJhdyBmcm9tIGl0PwogICsgSWYgd2UgY29uc3RydWN0IGEgbW9kZWwsIHRoZSB0eXBlIG9mIGNvbmNsdXNpb25zIHRoYXQgd2UnbGwgYmUgYWJsZSB0byBkcmF3IGZyb20gaXQgYXJlIGxpa2VseSB0byBiZSB3aGljaCB2YXJpYWJsZXMgYXJlIG1vc3QgaW1wb3J0YW50IHRvIGRldGVybWluZSB0aGUgbGlrZWxpaG9vZCBvZiBjYW5jZWxsYXRpb24uIFRoaXMgY291bGQgZWFzaWx5IGJlIGFjaGlldmVkIHVzaW5nIHRoZSBMQVNTTyB0ZWNobmlxdWUgdG8gYW5hbHl6ZSB2YXJpYWJsZSBpbXBvcnRhbmNlLgogIAoKKEApIENyZWF0ZSBzb21lIGV4cGxvcmF0b3J5IHBsb3RzIG9yIHRhYmxlIHN1bW1hcmllcyBvZiB0aGUgZGF0YSwgY29uY2VudHJhdGluZyBtb3N0IG9uIHJlbGF0aW9uc2hpcHMgd2l0aCB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIEtlZXAgaW4gbWluZCB0aGUgcmVzcG9uc2UgdmFyaWFibGUgaXMgbnVtZXJpYywgMCBvciAxLiBZb3UgbWF5IHdhbnQgdG8gbWFrZSBpdCBjYXRlZ29yaWNhbCAoeW91IGFsc28gbWF5IG5vdCkuIEJlIHN1cmUgdG8gYWxzbyBleGFtaW5lIG1pc3NpbmcgdmFsdWVzIG9yIG90aGVyIGludGVyZXN0aW5nIHZhbHVlcy4KCmBgYHtyfQpob3RlbHMgJT4lIAogIGdncGxvdChhZXMoeCA9IGhvdGVsKSkgKyAKICBnZW9tX2JhcihmaWxsID0gImJsdWUiKSArIAogIGZhY2V0X3dyYXAodmFycyhpc19jYW5jZWxlZCkpCmBgYApgYGB7cn0KaG90ZWxzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjdXN0b21lcl90eXBlKSkgKyAKICBnZW9tX2JhcihmaWxsID0gInJlZCIpICsKICBmYWNldF93cmFwKHZhcnMoaXNfY2FuY2VsZWQpKQpgYGAKCmBgYHtyfQpob3RlbHMgJT4lIAogIGdncGxvdChhZXMoeCA9IHByZXZpb3VzX2NhbmNlbGxhdGlvbnMpKSArCiAgZ2VvbV9iYXIoZmlsbCA9ICJvcmFuZ2UiKSArCiAgeGxpbSgwLDMpICsKICB5bGltKDAsNzAwMCkgKwogIGZhY2V0X3dyYXAodmFycyhpc19jYW5jZWxlZCkpCmBgYAoKCmBgYHtyfQpob3RlbHMgJT4lIAogIGdncGxvdChhZXMoeCA9IGFkdWx0cykpICsgCiAgZ2VvbV9iYXIoZmlsbCA9ICJncmVlbiIpICsKICB4bGltKDAsNSkgKwogIGZhY2V0X3dyYXAodmFycyhpc19jYW5jZWxlZCkpCmBgYApgYGB7cn0KaG90ZWxzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjaGlsZHJlbikpICsgCiAgZ2VvbV9iYXIoZmlsbCA9ICJncmVlbiIpICsKICB4bGltKDAsNSkgKwogIHlsaW0oMCwyNTAwKSArCiAgZmFjZXRfd3JhcCh2YXJzKGlzX2NhbmNlbGVkKSkKYGBgCgpgYGB7cn0KaG90ZWxzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBiYWJpZXMpKSArIAogIGdlb21fYmFyKGZpbGwgPSAiZ3JlZW4iKSArCiAgeGxpbSgwLDUpICsKICB5bGltKDAsMjAwKSArCiAgZmFjZXRfd3JhcCh2YXJzKGlzX2NhbmNlbGVkKSkKYGBgCgoKKEApIEZpcnN0LCB3ZSB3aWxsIGRvIGEgY291cGxlIHRoaW5ncyB0byBnZXQgdGhlIGRhdGEgcmVhZHksIGluY2x1ZGluZyBtYWtpbmcgdGhlIG91dGNvbWUgYSBmYWN0b3IgKG5lZWRzIHRvIGJlIHRoYXQgd2F5IGZvciBsb2dpc3RpYyByZWdyZXNzaW9uKSwgcmVtb3ZpbmcgdGhlIHllYXIgdmFyaWFibGUgYW5kIHNvbWUgcmVzZXJ2YXRpb24gc3RhdHVzIHZhcmlhYmxlcywgYW5kIHJlbW92aW5nIG1pc3NpbmcgdmFsdWVzIChub3QgTlVMTHMgYnV0IHRydWUgbWlzc2luZyB2YWx1ZXMpLiBTcGxpdCB0aGUgZGF0YSBpbnRvIGEgdHJhaW5pbmcgYW5kIHRlc3Qgc2V0LCBzdHJhdGlmeWluZyBvbiB0aGUgb3V0Y29tZSB2YXJpYWJsZSwgYGlzX2NhbmNlbGVkYC4gU2luY2Ugd2UgaGF2ZSBhIGxvdCBvZiBkYXRhLCB3ZeKAmXJlIGdvaW5nIHRvIHNwbGl0IHRoZSBkYXRhIDUwLzUwIGJldHdlZW4gdHJhaW5pbmcgYW5kIHRlc3QuIEkgaGF2ZSBhbHJlYWR5IGBzZXQuc2VlZCgpYCBmb3IgeW91LiBCZSBzdXJlIHRvIHVzZSBgaG90ZWxzX21vZGAgaW4gdGhlIHNwbGl0dGluZy4KCmBgYHtyfQpob3RlbHNfbW9kIDwtIGhvdGVscyAlPiUgCiAgbXV0YXRlKGlzX2NhbmNlbGVkID0gYXMuZmFjdG9yKGlzX2NhbmNlbGVkKSkgJT4lIAogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgYXMuZmFjdG9yKSkgJT4lIAogIHNlbGVjdCgtYXJyaXZhbF9kYXRlX3llYXIsCiAgICAgICAgIC1yZXNlcnZhdGlvbl9zdGF0dXMsCiAgICAgICAgIC1yZXNlcnZhdGlvbl9zdGF0dXNfZGF0ZSkgJT4lIAogIGFkZF9uX21pc3MoKSAlPiUgCiAgZmlsdGVyKG5fbWlzc19hbGwgPT0gMCkgJT4lIAogIHNlbGVjdCgtbl9taXNzX2FsbCkKCnNldC5zZWVkKDQ5NCkKYGBgCgpgYGB7cn0KaG90ZWxfc3BsaXQgPC0gaW5pdGlhbF9zcGxpdChob3RlbHNfbW9kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3AgPSAwLjUpCmhvdGVsX3RyYWluIDwtIHRyYWluaW5nKGhvdGVsX3NwbGl0KQpob3RlbF90ZXN0IDwtIHRlc3RpbmcoaG90ZWxfc3BsaXQpCmBgYAoKKEApIFByZS1wcm9jZXNzaW5nCgpgYGB7cn0KaG90ZWxfcmVjaXBlIDwtIHJlY2lwZShpc19jYW5jZWxlZCB+LiwKICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaG90ZWxfdHJhaW4pICU+JSAKICBzdGVwX211dGF0ZV9hdChjaGlsZHJlbiwgYmFiaWVzLCBwcmV2aW91c19jYW5jZWxsYXRpb25zLAogICAgICAgICAgICAgICAgIGZuID0gfmlmZWxzZSguID4gMCwgMSwgMCkpICU+JSAKICAgIHN0ZXBfbXV0YXRlX2F0KGFnZW50LCBjb21wYW55LAogICAgICAgICAgICAgICAgICBmbiA9IH5pZmVsc2UoLiA9PSAiTlVMTCIsIDEsIDApKSAlPiUgCiAgICAgIHN0ZXBfbXV0YXRlKGNvdW50cnkgPSBmY3RfbHVtcF9uKGNvdW50cnksIDUpKSAlPiUgCiAgICAgICAgc3RlcF9ub3JtYWxpemUoYWxsX251bWVyaWMoKSkgJT4lIAogICAgICAgICAgc3RlcF9kdW1teShhbGxfbm9taW5hbCgpLCAtYWxsX291dGNvbWVzKCkpCgpob3RlbF9yZWNpcGUgJT4lIAogIHByZXAoaG90ZWxfdHJhaW4pICU+JSAKICBqdWljZSgpCmBgYAoKCihAKSBMQVNTTyBtb2RlbCBhbmQgd29ya2Zsb3cKKiBXZSB3b3VsZCB3YW50IHRvIHVzZSBhIExBU1NPIHdvcmtmbG93IGJlY2F1c2UgTEFTU08gdXNlcyBhbiBpbXBvcnRhbmNlIGNvZWZmaWNpZW50IHdoaWNoIHJlZHVjZXMgdG8gemVybyB3aGVuIHRoZSB2YXJpYWJsZSBpcyBkZWVtZWQgdG8gYmUgbm90IHByZWRpY3RpdmUgb2Ygb3VyIG91dGNvbWUgdmFyaWFibGUuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byByZWR1Y2UgdGhlIHNpemUgb2Ygb3VyIGRhdGFzZXQgYW5kIG9ubHkgZm9jdXMgb24gb3VyIGluZGljYXRvciB2YXJpYWJsZXMgdGhhdCBtYXR0ZXIuCgogYGBge3J9CiMgbGFzc29faG90ZWxfbW9kIDwtIGxpbmVhcl9yZWcocGVuYWx0eSA9IHR1bmUoKSwgbW9kZSA9ICJyZWdyZXNzaW9uIikgJT4lCiMgICBzZXRfZW5naW5lKCJnbG1uZXQiKQojIAojIHdvcmtmbG93IDwtIHdvcmtmbG93KCkgJT4lIAojICAgYWRkX3JlY2lwZShob3RlbF9yZWNpcGUpICU+JSAKIyAgIGFkZF9tb2RlbChsYXNzb19ob3RlbF9tb2QpCiMgCiMgbGFzc29faG90ZWxfZml0IDwtIHdvcmtmbG93ICU+JSAKIyAgIGZpdChkYXRhID0gaG90ZWxfdHJhaW4pCiBgYGAKCgoKCg==